#!/bin/bash -e

# Copyright 2021 Flant JSC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

CONTAINER_NAME="deckhouse-testing"
TEST_TIMEOUT="15m"
export BASE_ALPINE=${BASE_ALPINE:-"alpine:3.12.1"}
export BASE_GOLANG_ALPINE=${BASE_GOLANG_ALPINE:-"golang:1.15.3-alpine3.12"}
export BASE_GOLANG_16_ALPINE=${BASE_GOLANG_16_ALPINE:-"golang:1.16.3-alpine3.12"}
export BASE_GOLANG_BUSTER=${BASE_GOLANG_BUSTER:-"golang:1.15.3-buster"}
export BASE_GOLANG_16_BUSTER=${BASE_GOLANG_16_BUSTER:-"golang:1.16.3-buster"}
export BASE_SHELL_OPERATOR=${BASE_SHELL_OPERATOR:-"flant/shell-operator:v1.3.2"}
export BASE_NGINX_ALPINE=${BASE_NGINX_ALPINE:-"nginx:1.15-alpine"}
export BASE_PYTHON_ALPINE=${BASE_PYTHON_ALPINE:-"python:3.7.9-alpine3.12"}
export BASE_UBUNTU=${BASE_UBUNTU:-"ubuntu:18.04"}
export BASE_JEKYLL=${BASE_JEKYLL:-"jekyll/jekyll:3.8"}

if [[ "$1" == "--debug" ]]; then
  DEBUG=yes
  shift

  # Override stdout and stderr for entire script
  exec >/tmp/deckhouse-testing-debug.log 2>&1
fi

file="$1"

if [[ $file =~ ^modules/.* ]]; then
  file="${file##modules/}"
  module_name="${file%%/*}"
  file="${file##${module_name}}"

  if [[ ! -d "modules/${module_name}" ]]; then
    echo "Directory 'modules/${module_name}' is not found or not accessible."
    exit 1
  fi

  if [[ $file =~ ^/hooks/.* ]]; then
    if [[ -f "modules/${module_name}${file}" ]]; then
      hook_name="$(basename "${file%%_test.go}")"
      tests=""
      docker_args="-w /deckhouse/modules/$module_name$(dirname "${file}")"

      if ! grep -q '\(FIt\|FDescribe\|FContext\) *(' "$(dirname "modules/${module_name}${file}")/${hook_name}_test.go"; then
        focus_args="-ginkgo.focus=${hook_name} -ginkgo.regexScansFilePath=true"
        ginkgo_args="--focus=${hook_name} --regexScansFilePath=true"
        echo "Run focused unit tests for module hook '${hook_name}'"
      else
        echo "Run all unit tests for module hook '${hook_name}'"
      fi
    else
      tests="./modules/$module_name${file}/..."
      echo "Run unit tests for module '${module_name}'"
    fi
  elif [[ $file == "/hooks" ]]; then
    tests="./modules/$module_name/hooks/..."
    echo "Run unit tests for all module hooks '${module_name}'"
  elif [[ $file =~ ^/(template_tests|templates)(/.*)? ]]; then
    tests="./modules/$module_name/template_tests/..."
    echo "Run template tests for module '${module_name}'"
  elif [[ $file == "/values_matrix_test.yaml" && -f "modules/${module_name}${file}" ]]; then
    docker_args="-e MODULES_DIR=/deckhouse/modules/${module_name} -w /deckhouse"
    ginkgo_args="-v --slowSpecThreshold=30"
    tests="./testing/matrix/..."
    echo "Run matrix tests for module '${module_name}'"
  else
    tests="./modules/$module_name/... ./testing/matrix/..."
    #tests="./modules/$module_name/hooks/... ./modules/$module_name/template_tests/...  ./testing/matrix/..."
    docker_args="-e MODULES_DIR=/deckhouse/modules/${module_name}"
    echo "Run unit tests and matrix tests for module '${module_name}'"
  fi
elif [[ $file == "modules" ]]; then
  tests="./modules/... ./testing/matrix/..."
  echo "Run unit tests and matrix tests for all modules"
elif [[ $file =~ ^global-hooks/.* ]]; then
  if [[ -f "${file}" ]]; then
    hook_name="$(basename "${file%%_test.go}")"
    tests=""
    docker_args="-w /deckhouse/$(dirname "${file}")"

    if ! grep -q '\(FIt\|FDescribe\|FContext\) *(' "$(dirname "${file}")/${hook_name}_test.go"; then
      focus_args="-ginkgo.focus=${hook_name} -ginkgo.regexScansFilePath=true"
      ginkgo_args="--focus=${hook_name} --regexScansFilePath=true"
      echo "Run focused unit tests for global hook '${hook_name}'"
    else
      echo "Run all unit tests for global hook '${hook_name}'"
    fi
  fi
elif [[ $file == global-hooks ]]; then
  tests="./global-hooks/..."
  echo "Run unit tests for all global hooks"
elif [[ $file =~ ^testing/matrix$ || $file =~ ^matrix$ ]]; then
  docker_args="-e MODULES_DIR=/deckhouse/modules -w /deckhouse"
  ginkgo_args="-v --slowSpecThreshold=30"
  tests="./testing/matrix/..."
  echo "Run all matrix tests"
elif [[ $file =~ ^testing/hooks_configuration$ || $file =~ ^hooks_configuration$ || $file =~ ^testing/hooks_configuration/hooks_configuration_test.go$ ]]; then
  docker_args="-w /deckhouse"
  ginkgo_args="-v --slowSpecThreshold=30"
  tests="./testing/hooks_configuration/"
  echo "Run hooks configuration tests"
elif [[ "$file" == "." ]]; then
  tests="./..."
  echo "Run tests in current directory"
fi

if [[ -z "$tests" && -z "$docker_args" && -z "$focus_args" ]]; then
  >&2 echo "ERROR: Don't know how to run tests for \"$1\""
  exit 1
fi

if [[ -z "$(docker ps --filter "name=$CONTAINER_NAME" -q)" ]]; then
  PATH="$HOME/bin/:$PATH"
  # shellcheck disable=SC2046
  echo ${DECKHOUSE_DEV_REGISTRY_PASSWORD} | docker login --username="${DECKHOUSE_DEV_REGISTRY_USER}" --password-stdin ${DECKHOUSE_DEV_REGISTRY_HOST} 2>/dev/null
  echo ${DECKHOUSE_REGISTRY_PASSWORD} | docker login --username="${DECKHOUSE_REGISTRY_USER}" --password-stdin ${DECKHOUSE_REGISTRY_HOST} 2>/dev/null
  echo ${DECKHOUSE_REGISTRY_READ_PASSWORD} | docker login --username="${DECKHOUSE_REGISTRY_READ_USER}" --password-stdin ${DECKHOUSE_REGISTRY_READ_HOST} 2>/dev/null
  type multiwerf && source $(multiwerf use 1.2 ${WERF_CHANNEL:-ea} --as-file)
  export WERF_REPO=${DEV_REGISTRY_PATH:-"dev-registry.deckhouse.io/sys/deckhouse-oss"}

  werf build tests
  # shellcheck disable=SC2016
  werf run tests \
    --docker-options="-v $(pwd):/deckhouse --name $CONTAINER_NAME --rm -d -w /deckhouse -p 127.0.0.1:4284:4284" \
    -- \
    dumb-init -- bash -c 'touch /last-used; while [[ -z "$(find /last-used -mmin +60)" ]]; do sleep 60; done'
fi

docker exec "$CONTAINER_NAME" touch /last-used

if [[ "$DEBUG" == "yes" ]]; then
  # TODO: Kill dlv and all parents when stop is pressed in IDE

  docker exec "$CONTAINER_NAME" killall dlv || true

  echo "Running: docker exec $docker_args $CONTAINER_NAME dlv test --headless --listen 0.0.0.0:4284 --api-version 2 -- -vet=off $tests $focus_args ..."

  # shellcheck disable=SC2086
  docker exec $docker_args "$CONTAINER_NAME" \
    dlv test --headless --listen 0.0.0.0:4284 --api-version 2 -- $tests $focus_args \
    >>/tmp/deckhouse-testing-debug.log 2>&1 &

  while ! docker exec "$CONTAINER_NAME" netstat -nlt | grep -q '4284.*LISTEN'; do
    sleep 0.1
  done
else
  cmd="ginkgo -vet=off -timeout=$TEST_TIMEOUT $ginkgo_args $tests"
  echo "Running: docker exec $docker_args $CONTAINER_NAME bash -c \"$cmd\""

  cmd="$cmd &$(
    cat <<"END"
pid=$!
touch /test-is-not-stopped
while kill -0 $pid 2>/dev/null; do
  if (( $(date +%s) - $(date +%s -r /test-is-not-stopped) > 1 )) ; then
    pkill -P $pid 2>/dev/null
    kill $pid 2>/dev/null
  fi
  sleep 0.1
done
END
  )"

  # shellcheck disable=SC2086
  docker exec $docker_args "$CONTAINER_NAME" bash -c "$cmd" &

  pid=$!
  # shellcheck disable=SC2009
  while kill -0 $pid 2>/dev/null; do
    docker exec "$CONTAINER_NAME" touch /test-is-not-stopped
    sleep 0.1
  done
fi
